
/*
 * Hlpay-Plus aggregate payment system.
 * Copyright (c) 2024-2025 Hlpay Team Copyright has the right of final interpretation.
 *
 */

package com.hlkj.pay.app.token.ext.impl;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.hlkj.framework.caches.service.RedisTemplateService;
import com.hlkj.framework.common.pojo.CommonResult;
import com.hlkj.framework.common.provider.Aes256EncryptionProvider;
import com.hlkj.framework.extension.annotation.Extension;
import com.hlkj.pay.app.token.ext.AuthTokenExtPt;
import com.hlkj.pay.common.AdminUserResultCode;
import com.hlkj.pay.common.CommonResultCode;
import com.hlkj.pay.common.TenantSecretContext;
import com.hlkj.pay.common.constants.TenantAuthConstant;
import com.hlkj.pay.common.constants.TokenRedisConstant;
import com.hlkj.pay.dto.admin.AdminUserDto;
import com.hlkj.pay.enums.AuthTokenEnum;
import com.hlkj.pay.infrastructure.model.token.TokenSecretDO;
import com.hlkj.pay.service.admin.IAdminUserService;
import com.hlkj.pay.service.token.impl.TokenCommonService;
import com.hlkj.pay.vo.common.req.token.AuthTokenClientRequest;
import com.hlkj.pay.vo.common.req.token.PasswordTokenRequest;
import com.hlkj.pay.vo.common.resp.token.OauthTokenResp;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * @author HlpayTeam
 * @date 2024/09/30 10:42
 */
@Slf4j
@Service
@Extension(bizId = TenantAuthConstant.ADMIN_PASSWORD)
@RequiredArgsConstructor
public class AdminPassWordTokenServiceExt extends AdminLoginCommonCheck implements AuthTokenExtPt {

    private final IAdminUserService adminUserService;

    private final TokenCommonService tokenCommonService;

    private final RedisTemplateService redisTemplateService;

    @Value("${auth.password.error.num}")
    private Integer passwordErrorNum;

    @Value("${auth.password.error.expireTime}")
    private Integer passwordErrorExpireTime;

    private final Aes256EncryptionProvider aes256EncryptionProvider;

    /**
     * OauthTokenResp
     * 
     * @return
     */
    @Override
    public CommonResult<OauthTokenResp> oauthToken(AuthTokenClientRequest authTokenClientRequest) {
        TokenSecretDO tenantSecretDO = TenantSecretContext.get();
        PasswordTokenRequest passwordTokenRequest = (PasswordTokenRequest) authTokenClientRequest;
        String userNameKey = userNameKey(passwordTokenRequest.getUserName());
        Object object = redisTemplateService.get(userNameKey);
        if (object != null) {
            if (passwordErrorNum < (Integer) object) {
                CommonResult<OauthTokenResp> commonResult = CommonResult.error(CommonResultCode.TOKEN_USER_PWD_NUM_ERROR);
                OauthTokenResp oauthTokenResp = new OauthTokenResp();
                oauthTokenResp.setErrorNum((Integer) object);
                commonResult.setData(oauthTokenResp);
                return commonResult;
            }
        }
        AdminUserDto adminUserDto = adminUserService.queryUserByAccount(passwordTokenRequest.getUserName());
        CommonResult<Void> voidCommonResult = checkUser(tenantSecretDO, adminUserDto);
        if (!voidCommonResult.isSuccess()) {
            return CommonResult.error(voidCommonResult.getCode(), voidCommonResult.getMsg());
        }
        String pwd = null;
        try {
            pwd = aes256EncryptionProvider.encryptString(passwordTokenRequest.getPassword());
        }
        catch (Exception e) {
            return CommonResult.error(CommonResultCode.DATA_DECRYPT_ERROR);
        }
        if (!pwd.equals(adminUserDto.getPwdEncrypt())) {
            redisTemplateService.incr(userNameKey, 1);
            redisTemplateService.expire(userNameKey, passwordErrorExpireTime);
            CommonResult<OauthTokenResp> commonResult = CommonResult.error(AdminUserResultCode.USER_PWD_ERROR);
            OauthTokenResp oauthTokenResp = new OauthTokenResp();
            oauthTokenResp.setErrorNum((Integer) object);
            commonResult.setData(oauthTokenResp);
            return commonResult;
        }
        else {
            redisTemplateService.set(userNameKey, 0);
        }
        OauthTokenResp oauthTokenResp;
        AuthTokenEnum.AUTH_TOKEN_REQUEST_TYPE authTokenClientType = AuthTokenEnum.AUTH_TOKEN_REQUEST_TYPE.PASSWORD;
        // 多因子认证
        // if (AdminUserEnum.YES_NO_TYPE.YES.getCode().equals(data.getMfaFlag())) {
        // oauthTokenResp = tokenCommonService.mfaAccessToken(tenantSecretDO,
        // data.getId());
        // authTokenClientType = AuthTokenEnum.AUTH_TOKEN_REQUEST_TYPE.MFA;
        // }
        // else {
        // 普通认证
        oauthTokenResp = tokenCommonService.userToken(tenantSecretDO, adminUserDto.getId(), adminUserDto.getSn());
        // }
        tokenCommonService.addTenantAuthLog(tenantSecretDO, oauthTokenResp, authTokenClientType);
        oauthTokenResp.setMfaLoginType(adminUserDto.getMfaFlag());
        return CommonResult.success(oauthTokenResp);
    }

    /**
     * clientTokenKey
     * 
     * @param userName
     * @return
     */
    String userNameKey(String userName) {
        StringBuilder sb = new StringBuilder(TokenRedisConstant.TOKEN_CLIENT_AUTH);
        // sb.append(tenantId);
        // sb.append(StringPool.COLON);
        sb.append(userName);
        return sb.toString();
    }
}
